package com.acoreful.acf2java.commons.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * httpclient的工具类
 * 
 * @author wh
 * @since 0.0.1
 */
public abstract class HttpClientUtils {

	private static final Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);

	private static PoolingHttpClientConnectionManager connMgr;
	private static RequestConfig requestConfig;
	private static final int MAX_TIMEOUT = 7000;
	static {
		// 设置连接池
		connMgr = new PoolingHttpClientConnectionManager();
		// 设置连接池大小
		connMgr.setMaxTotal(100);
		connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());
		connMgr.setValidateAfterInactivity(3);

		RequestConfig.Builder configBuilder = RequestConfig.custom();
		// 设置连接超时
		configBuilder.setConnectTimeout(MAX_TIMEOUT);
		// 设置读取超时
		configBuilder.setSocketTimeout(MAX_TIMEOUT);
		// 设置从连接池获取连接实例的超时
		configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);
		requestConfig = configBuilder.build();
	}

	public static String httpPost(String uri, Map<String, String> requestParams) {
		return httpPost(uri, requestParams, new HashMap<>(0));
	}

	public static String httpPost(String uri, Map<String, String> requestParams, Map<String, String> headers) {
		return httpPost(uri, requestParams, "UTF-8", headers, 20000, 60000);
	}

	public static String httpPost(String uri, Map<String, String> requestParams, String contentEncoding,
			Map<String, String> headers, int connectionTimeout, int soTimeout) {
		CloseableHttpClient httpClient = HttpClientBuilder.create()
				.setDefaultRequestConfig(
						RequestConfig.custom().setConnectTimeout(connectionTimeout).setSocketTimeout(soTimeout).build())
				.build();

		HttpPost postMethod = new HttpPost(uri);

		List<NameValuePair> parameters = new ArrayList<>(requestParams.size());
		requestParams.forEach((name, value) -> {
			parameters.add(new BasicNameValuePair(name, value));
		});

		headers.forEach((name, value) -> {
			postMethod.setHeader(name, value);
		});

		CloseableHttpResponse response = null;
		String responseString = "";
		try {
			UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, contentEncoding);
			postMethod.setEntity(formEntity);

			response = httpClient.execute(postMethod);
			HttpEntity entity = response.getEntity();
			responseString = EntityUtils.toString(entity, contentEncoding);
		} catch (Throwable e) {
			logger.error(e.getMessage());
		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
					logger.error(e.getMessage());
				}
			}
		}
		return responseString;
	}

	public static String httpPost(String uri, String requestBody) {
		return httpPost(uri, requestBody, new HashMap<>(0));
	}

	public static String httpPost(String uri, String requestBody, Map<String, String> headers) {
		return httpPost(uri, requestBody, "UTF-8", headers, 20000, 60000);
	}

	public static String httpPost(String uri, String requestBody, String charset, Map<String, String> headers,
			int connectionTimeout, int soTimeout) {
		CloseableHttpClient httpClient = HttpClientBuilder.create()
				.setDefaultRequestConfig(
						RequestConfig.custom().setConnectTimeout(connectionTimeout).setSocketTimeout(soTimeout).build())
				.build();

		HttpPost postMethod = new HttpPost(uri);

		headers.forEach((name, value) -> {
			postMethod.setHeader(name, value);
		});

		CloseableHttpResponse response = null;
		String responseString = "";
		try {

			StringEntity stringEntity = new StringEntity(requestBody, ContentType.APPLICATION_JSON);
			postMethod.setEntity(stringEntity);

			response = httpClient.execute(postMethod);
			HttpEntity entity = response.getEntity();
			responseString = EntityUtils.toString(entity, charset);
		} catch (Throwable e) {
			logger.error(e.getMessage());
		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
					logger.error(e.getMessage());
				}
			}
		}
		return responseString;
	}

	/**
	 * @param uri
	 * @param requestBody
	 * @param keyStorePath
	 * @param keyStorepass
	 * @param headers
	 * @return
	 */
	public static String httpPostSSL(String uri, String requestBody,String keyStorePath, String keyStorepass) {
		return httpPostSSL(uri, requestBody, keyStorePath, keyStorepass,null);
	}
	/**
	 * @param uri
	 * @param requestBody
	 * @param keyStorePath
	 * @param keyStorepass
	 * @param headers
	 * @return
	 */
	public static String httpPostSSL(String uri, String requestBody,String keyStorePath, String keyStorepass,Map<String, String> headers) {
		SSLConnectionSocketFactory sslConnectionSocketFactory=new SSLConnectionSocketFactory(custom(keyStorePath, keyStorepass),new String[] { "TLSv1" }, null,
				SSLConnectionSocketFactory.getDefaultHostnameVerifier());
		CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory)
				.setDefaultRequestConfig(requestConfig).build();

		HttpPost postMethod = new HttpPost(uri);
		if(headers!=null){
			headers.forEach((name, value) -> {
				postMethod.setHeader(name, value);
			});
		}
		CloseableHttpResponse response = null;
		String responseString = "";
		try {

			StringEntity stringEntity = new StringEntity(requestBody);
			stringEntity.setContentType("application/x-www-form-urlencoded");
			postMethod.setEntity(stringEntity);
			response = httpClient.execute(postMethod);
			HttpEntity entity = response.getEntity();
			responseString = EntityUtils.toString(entity, "UTF-8");
		} catch (Throwable e) {
			logger.error(e.getMessage());
		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
					logger.error(e.getMessage());
				}
			}
		}
		return responseString;
	}

	/**
     * 设置信任自签名证书
     *     
     * @param keyStorePath        密钥库路径
     * @param keyStorepass        密钥库密码
     * @return
     */
    public static SSLContext custom(String keyStorePath, String keyStorepass){
        SSLContext sc = null;
        FileInputStream instream = null;
        KeyStore trustStore = null;
        try {
            trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            instream = new FileInputStream(new File(keyStorePath));
            trustStore.load(instream, keyStorepass.toCharArray());
            // 相信自己的CA和所有自签名的证书
            sc = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
        } catch (KeyStoreException | NoSuchAlgorithmException| CertificateException | IOException | KeyManagementException e) {
            e.printStackTrace();
        } finally {
            try {
                instream.close();
            } catch (IOException e) {
            }
        }
        return sc;
    }

}
